package com.eastfair.pay.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eastfair.boot.request.PageParams;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.core.utils.ConvertUtil;
import com.eastfair.pay.dao.PaymentPlanMapper;
import com.eastfair.pay.dto.PaymentPlanDTO;
import com.eastfair.pay.dto.PaymentPlanPageQuery;
import com.eastfair.pay.entity.CollectRecord;
import com.eastfair.pay.entity.Contract;
import com.eastfair.pay.entity.PaymentPlan;
import com.eastfair.pay.enums.PayStateEnum;
import com.eastfair.pay.exceptioncode.PayExceptionCode;
import com.eastfair.pay.service.CollectRecordService;
import com.eastfair.pay.service.ContractService;
import com.eastfair.pay.service.PaymentPlanService;
import com.eastfair.pay.vo.CollectRecordVO;
import com.eastfair.pay.vo.PaymentPlanVO;
import io.seata.common.util.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 付款计划
 * </p>
 *
 * @author clm
 * @date 2022-06-08
 */
@Slf4j
@Service
//@DS("#thread.tenant")
public class PaymentPlanServiceImpl extends SuperServiceImpl<PaymentPlanMapper, PaymentPlan> implements PaymentPlanService {

    @Autowired
    private CollectRecordService collectRecordService;
    @Autowired
    private ContractService contractService;
    @Autowired
    private PaymentPlanMapper paymentPlanMapper;

    /**
     * 处理新增相关处理
     *
     * @param model 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerSave(PaymentPlan model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        return R.successDef();
    }

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<PaymentPlan> modelList) {
        modelList.stream().forEach(s -> {
            s.setIsDeleted(BusinessConstant.YES);
        });
        // TODO: 2021/10/29 这里需要操作其他业务，如清空角色等
        return R.successDef();
    }


    /**
     * 通过业务id 获取付款计划
     * @param businessId
     * @return
     */
    @Override
    public List<PaymentPlan> queryByBusinessId(Long businessId) {
        LambdaQueryWrapper<PaymentPlan> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PaymentPlan::getBusinessId, businessId);
        lambdaQueryWrapper.orderByAsc(PaymentPlan::getStagesTag);
        return baseMapper.selectList(lambdaQueryWrapper);
    }

    @Override
    public List<PaymentPlanVO> listByPlanPayTime(String startPlanPayTime, String endPlanPayTime) {
        log.info("listByPlanPayTime - 计划付款时间范围查询未付款的付款计划, startPlanPayTime={}, endPlanPayTime={}",
                startPlanPayTime, endPlanPayTime);
        QueryWrapper<PaymentPlan> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(PaymentPlan::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(PaymentPlan::getPayState, PayStateEnum.UN_PAY.getCode())
                .between(StrUtil.isNotBlank(startPlanPayTime) && StrUtil.isNotBlank(endPlanPayTime),
                        PaymentPlan::getPlanPayTime, startPlanPayTime, endPlanPayTime)
        ;
        List<PaymentPlan> list = list(queryWrapper);
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
        return list
                .stream()
                .map(paymentPlan -> BeanUtil.toBean(paymentPlan, PaymentPlanVO.class))
                .collect(Collectors.toList());
    }

    /**
     * 删除
     * @param planId
     */
    @Override
    public void deleteById(Long planId) {
        List<CollectRecordVO> collectRecordVOS = collectRecordService.queryCollectByPlanId(planId);
        if (!CollectionUtil.isEmpty(collectRecordVOS)){
            throw BizException.wrap(PayExceptionCode.ALREADY_COLLECT);
        }
        removeById(planId);
    }

    /**
     * 保存更新
     *
     * @param paymentPlanDTOs
     * @return
     */
    @Override
    public String saveOrupdate(List<PaymentPlanDTO> paymentPlanDTOs) {

        if (CollectionUtil.isEmpty(paymentPlanDTOs)){
            throw BizException.wrap(PayExceptionCode.CONTRACT_PAYMENT_PLAN_ISNULL);
        }

        StringBuffer failPlan = new StringBuffer();
        Long contractId = paymentPlanDTOs.get(0).getBusinessId();
        Contract contract = contractService.getByBusinessId(contractId);

        if (contract == null){
            throw BizException.wrap(PayExceptionCode.CONTRACT_NOT_EXTIS);
        }

        List<CollectRecord> collectRecordList = collectRecordService.queryCollectRecordList(contractId);
        Map<Long, List<CollectRecord>> collect = MapUtil.empty();
        if (!CollectionUtil.isEmpty(collectRecordList)){
            collect = collectRecordList.stream().collect(Collectors.groupingBy(CollectRecord::getPaymentPlanId));
        }

        List<PaymentPlan> paymentPlans = ConvertUtil.convertList(paymentPlanDTOs, PaymentPlan.class);
        BigDecimal planAmount =new BigDecimal(0);
        Iterator<PaymentPlan> iterator = paymentPlans.iterator();
        while (iterator.hasNext()){
            PaymentPlan paymentPlan = iterator.next();
            planAmount = planAmount.add(paymentPlan.getPlanPayAmount());
            //如有认款记录则修改失败
            if(!CollectionUtil.isEmpty(collect.get(paymentPlan.getId()))){
                failPlan.append(paymentPlan.getStagesTag() + ",");
                iterator.remove();
            }
        }

        //判断合同金额是否等于付款计划总和
        if (contract.getContractAmount().compareTo(planAmount) != 0){
            throw BizException.wrap(PayExceptionCode.CONTRACT_PLAN_AMOUNT_NOT_EQ);
        }

        List<PaymentPlan> saveList = new ArrayList<>();
        List<PaymentPlan> updateList = new ArrayList<>();

        for (PaymentPlan paymentPlan : paymentPlans){
            if (paymentPlan.getId() == null){
                saveList.add(paymentPlan);
            } else {
                updateList.add(paymentPlan);
            }
        }

        updateBatchById(updateList);
        saveBatch(saveList);
        String res = failPlan.toString();
        return StrUtil.isBlank(res) ? res : res.substring(0, res.length() - 1);
    }

    /**
     * @param params
     * @return
     */
    @Override
    public Page<PaymentPlanVO> queryPage(PageParams<PaymentPlanPageQuery> params) {

        PaymentPlanPageQuery model = params.getModel();
        LambdaQueryWrapper<PaymentPlan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(!StrUtil.isBlank(model.getPayState()) , PaymentPlan::getPayState, model.getPayState());
        queryWrapper.between(model.getPlanPayStartTime() != null && model.getPlanPayEndTime() != null, PaymentPlan::getPlanPayTime, model.getPlanPayStartTime(), model.getPlanPayEndTime());
        queryWrapper.and(!StrUtil.isBlank(model.getKeyWords()), paymentPlanLambdaQueryWrapper -> paymentPlanLambdaQueryWrapper
                .like(PaymentPlan::getBusinessName, model.getKeyWords())
                .or().like(PaymentPlan::getExhibitionName, model.getKeyWords())
        );

        Page<PaymentPlan> paymentPlanPage = params.buildPage();
        Page<PaymentPlan> page = page(paymentPlanPage, queryWrapper);

        //更新支付过期状态
        List<PaymentPlan> paymentPlans = page.getRecords();
        List<PaymentPlan> updatePlans = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(paymentPlans)){
            for(PaymentPlan payment : paymentPlans){
                if (payment.getPlanPayTime().compareTo(LocalDateTime.now()) == -1 && !PayStateEnum.PAYED.getCode().equals(payment.getPayState())){
                    payment.setPayState(PayStateEnum.IS_EXPIRES.getCode());
                    updatePlans.add(payment);
                }
            }
        }
        updateBatchById(updatePlans);

        Page<PaymentPlanVO> paymentPlanVOPage = ConvertUtil.convertPage(page, PaymentPlanVO.class);
        List<PaymentPlanVO> records = paymentPlanVOPage.getRecords();
        Map<Long, List<PaymentPlanVO>> collect = records.stream().collect(Collectors.groupingBy(PaymentPlanVO::getBusinessId, Collectors.toList()));
        if (!CollectionUtil.isEmpty(records)){
            for (PaymentPlanVO paymentPlanVO : records){
                paymentPlanVO.setStagesTagStr("第" + paymentPlanVO.getStagesTag() + "期"+ "(" +collect.get(paymentPlanVO.getBusinessId()).size()+"期)");
            }
        }
        return paymentPlanVOPage;
    }

    /**
     * 通过合同删除付款计划
     * @param contractId
     */
    @Override
    public void deleteByContractId(Long contractId) {
        LambdaQueryWrapper<PaymentPlan> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(contractId != null, PaymentPlan::getBusinessId, contractId);
        baseMapper.delete(lambdaQueryWrapper);
    }

    @Override
    public List<PaymentPlan> queryByBusinessNumber(String businessNumber) {
        List<Contract> contractList = contractService.lambdaQuery().eq(Contract::getContractNumber, businessNumber).orderByDesc(Contract::getCreateTime).list();
        if (CollectionUtils.isEmpty(contractList)){
            log.error("合同不存在,businessNumber={}",businessNumber);
            throw BizException.wrap(PayExceptionCode.CONTRACT_NOT_EXTIS);
        }
        Contract contract = contractList.get(0);
        LambdaQueryWrapper<PaymentPlan> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PaymentPlan::getBusinessId, contract.getContractId());
        lambdaQueryWrapper.orderByAsc(PaymentPlan::getStagesTag);
        return baseMapper.selectList(lambdaQueryWrapper);
    }
}
